package cfca.paperless.client.servlet.customer;

import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import cfca.com.itextpdf.text.pdf.PdfArray;
import cfca.com.itextpdf.text.pdf.PdfReader;
import cfca.com.itextpdf.text.pdf.security.PdfPKCS7;
import cfca.paperless.client.bean.MultiDataBean;
import cfca.paperless.client.bean.SignLocation;
import cfca.paperless.client.servlet.PaperlessClient;
import cfca.paperless.client.servlet.PaperlessCloudConfig;
import cfca.paperless.client.util.Base64;
import cfca.paperless.client.util.IoUtil;
import cfca.paperless.client.util.PaperlessUtil;
import cfca.paperless.client.util.PdfUtil;
import cfca.paperless.client.util.ReservedPdfPKCS7Util;
import cfca.paperless.client.util.StringUtil;
import cfca.sadk.algorithm.common.Mechanism;
import cfca.sadk.util.HashUtil;
import cfca.sadk.x509.certificate.X509Cert;
import cfca.seal.sadk.DonePdfSeal;
import cfca.seal.sadk.PdfSealVerifier;
import cfca.seal.sadk.PrePdfSealExtra;
import cfca.seal.sadk.security.deferred.ReservedPdfPKCS7;

public class testSignAutoPdfHash_haierrzzl {

    /**
     * PDF自动化Hash签名接口,计算hash，本地合成签名
     * 
     * @param args
     * @throws IOException
     * @throws
     */
    public static void main(String[] args) throws Exception {
        try {
            long timeStart = System.currentTimeMillis();// 开始时间
            // 待签章pdf
            String filePath = "./TestData/file.pdf";
            byte[] pdf = FileUtils.readFileToByteArray(new File(filePath));
            // 印模图片
            byte[] handwritingImage = FileUtils.readFileToByteArray(new File("./TestData/image.png"));
            // 如下为本地合成的多媒体信息
//            byte[] handwritingData = handwritingImage;
            byte[] identificationFrontData = FileUtils.readFileToByteArray(new File("./TestData/1.png"));
            byte[] identificationBackData = FileUtils.readFileToByteArray(new File("./TestData/2.png"));
            // List<MultiDataBean> list = new ArrayList<MultiDataBean>();
            // list.add(new MultiDataBean(handwritingData,
            // "handwritingData.dat", "2"));//手写签名数据
            // list.add(new MultiDataBean(handwritingImage,
            // "handwritingImage.png", "2"));//手写签名图片
            // list.add(new MultiDataBean(identificationFrontData,
            // "identificationFrontImage.png", "2"));//身份证正面
            // list.add(new MultiDataBean(identificationBackData,
            // "identificationBackImage.png", "2"));//身份证反面
            //
            // //添加多媒体数据到pdf
            // pdf = addMultiDataToPdf(pdf, list);

            String sealCode = "org001";// 印章编码
            String sealPassword = "";// 印章密码
            // 获取印章公钥证书
            X509Cert x509Cert = getX509CertBySealCode(sealCode);
            System.out.println(x509Cert.getSubject());

            SignLocation signLocation = new SignLocation("代理人签名", "R", 20, 10);// 签名位置
            ReservedPdfPKCS7 reservedPdfPKCS7 = new ReservedPdfPKCS7();// 创建临时数据保存对象
            // 计算保留值
            String timestampServer[] = new String[]{"http://210.74.41.195/timestamp","",""};
            PrePdfSealExtra prePdfSealExtra = new PrePdfSealExtra("业务", "china");
            String hashAlogrithmArg = "SHA1";
            byte[] reservedPdf = ReservedPdfPKCS7Util.createReservedPdf(pdf, handwritingImage, 0.75f, x509Cert, hashAlogrithmArg, signLocation, reservedPdfPKCS7, timestampServer, prePdfSealExtra);
            // 如下数据需要保存到数据库
            String reservedData = ReservedPdfPKCS7Util.createReservedVar(reservedPdfPKCS7);
            // 计算hash
            byte[] pdfSealHash = HashUtil.RSAHashMessageByBC(reservedPdfPKCS7.signatureAttr, new Mechanism(Mechanism.SHA1), false);
            // 组装PdfHash签名接口报文
            String pdfHashSignListXml = createPdfHashSignXml(pdfSealHash, sealCode, sealPassword);

            // 组装短信验证码
            String authCodeXml = "<AuthCode><AuthCodeValue>230442</AuthCodeValue><AuthCodeId>201608301144556858459229015265</AuthCodeId></AuthCode>";
            // 初始化客户端对象
            PaperlessClient clientBean = new PaperlessClient("http://127.0.0.1:8080/Proxy/PaperlessServer", 10000, 60000);// 无纸化辅助接口的访问URL

            // 调用 pdfhash签名接口
            String signMessage = clientBean.signAutoPdfHash(pdfHashSignListXml, "", PaperlessCloudConfig.operatorCode, PaperlessCloudConfig.channelCode);

            String code = StringUtil.getNodeText(signMessage, "Code");
            if ("200".equals(code)) {
                System.out.println("OK:autoCalculatePdfHash");
                Object[] signedBeanArr = StringUtil.getXmlFieldArr(signMessage, "SignedBean");
                // 获取签名值
                String pkcs1 = StringUtil.getNodeText((String) signedBeanArr[0], "Pkcs1");
                System.out.println("返回的pkcs1：" + pkcs1);
                // 恢复reservedPdfPKCS7对象
                reservedPdfPKCS7 = ReservedPdfPKCS7Util.initReservedVar(reservedData);
                reservedPdfPKCS7.signaturePKCS1 = Base64.decode(pkcs1);
                // 合成外部签名
                DonePdfSeal donePdfSeal = new DonePdfSeal();
                byte[] sealedPdfData = donePdfSeal.mergeReservedPdfSeal(new PdfReader(reservedPdf), reservedPdfPKCS7);
                // 验证 pdf签章
                PdfSealVerifier pdfSealVerifier = new PdfSealVerifier(sealedPdfData);
                if (!pdfSealVerifier.isPKCS7Valid()) {
                    System.out.println("pdfSealVerifier error");
                    IoUtil.write("./TestData/output/signAutoPdfProofHash2-error.pdf", sealedPdfData);
                } else {
                    PdfArray uncoverdRange = pdfSealVerifier.getUncoveredByteRange();
                    long uncoverdRangeLen = uncoverdRange.asLongArray()[1];
                    if (uncoverdRangeLen > 0) {
                        System.out.println(" 单据在盖章之后被修改 ");
                    }
                    // 验证后获取签章时间和证书主题
                    Map<String, X509Cert> sigNameCertMap = pdfSealVerifier.getSigNameCertMap();
                    Map<String, PdfPKCS7> sigNamePKCS7Map = pdfSealVerifier.getSigNamePKCS7Map();
                    List<X509Cert> x509CertList = new ArrayList<X509Cert>(sigNameCertMap.values());
                    List<PdfPKCS7> pdfPKCS7List = new ArrayList<PdfPKCS7>(sigNamePKCS7Map.values());
                    Calendar calendar = pdfPKCS7List.get(0).getSignDate();
                    Date date = calendar.getTime();
                    System.out.println("签章时间：" + date.toLocaleString());
                    System.out.println("签章证书主题:" + x509CertList.get(0).getSubject());
                    String outputFilePath = "./TestData/output/signAutoPdfProofHash2-" + new File(filePath).getName() + ".pdf";
                    System.out.println("pdfSealVerifier ok " + outputFilePath);
                    IoUtil.write(outputFilePath, sealedPdfData);
                }
            } else {
                System.out.println("" + signMessage);
            }

            long timeEnd = System.currentTimeMillis();// 结束时间
            System.out.println("time:" + (timeEnd - timeStart));

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private static String createPdfHashSignXml(byte[] pdfSealHash, String sealCode, String sealPassword) throws Exception {
        // 组装PdfHash签名接口报文
        String pdfHashSignListXml = "<List><PdfHashSign>" + "<PdfSealHash>" + Base64.toBase64String(pdfSealHash) + "</PdfSealHash>"
                + "<PdfSealSource></PdfSealSource>" + "<BizTypeCode></BizTypeCode>" + "<SealCode>" + sealCode + "</SealCode>" + "<SealPassword>" + sealPassword
                + "</SealPassword>" + "</PdfHashSign></List>";

        return pdfHashSignListXml;
    }

    private static byte[] addMultiDataToPdf(byte[] pdf, List<MultiDataBean> list) throws Exception {
        String proofHashAndMultiData1[] = PaperlessUtil.getProofHashAndMultiData(list);
        String proofHashXml = proofHashAndMultiData1[0];
        // 计算pdf内容hash
        String pdfContentHash = PdfUtil.calculatePdfContentHash(pdf, new Mechanism(Mechanism.SHA1));
        proofHashXml = addProofToXml(proofHashXml, "pdfHash.pdf", pdfContentHash);
        // 合成proofHash
        pdf = PdfUtil.compoundPdfDataByAttachment(pdf, proofHashXml.getBytes(), "proofHash.xml");
        // 合成多媒体文件
        for (MultiDataBean multiDataBean : list) {
            pdf = PdfUtil.compoundPdfDataByAttachment(pdf, multiDataBean.getMultiData(), multiDataBean.getFileName());
        }
        return pdf;
    }

    private static X509Cert getX509CertBySealCode(String sealCode) throws Exception {
        X509Cert x509Cert = null;
        // 以下代码为获取印章编码对应公钥证书
        PaperlessClient clientAssistBean = new PaperlessClient(PaperlessCloudConfig.assistUrl, 10000, 60000);// 无纸化辅助接口的访问URL

        String result = clientAssistBean.getSealInfo(sealCode, PaperlessCloudConfig.operatorCode);
        String code = StringUtil.getNodeText(result, "Code");
        if (!code.equals("200")) {
            System.out.println("error:getSealInfo");
            System.out.println(result);
        } else {
            x509Cert = new X509Cert(Base64.decode(StringUtil.getNodeText(result, "SealCert")));
        }
        return x509Cert;
    }

    private static String addProofToXml(String xmlContent, String fileName, String hash) throws DocumentException {
        Document document = DocumentHelper.parseText(xmlContent);
        Element root = document.getRootElement();
        Element newElement = root.addElement("Proof");
        newElement.addAttribute("fileName", fileName);
        newElement.addAttribute("hash", hash);
        return document.asXML();
    }

}
